#include "disk.h"

STATIC CONST WORD wPort[] = {0x1F2, 0x172};

VOID DevHardDiskRead(BYTE bNo, DWORD dwLBAAddress, BYTE bReadNumber, LPVOID lpvBuffer) {
    __asm__("out %%al,%%dx\n"
            "inc %%dx\n"
            "mov %4,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "and $0x0F,%%al\n"
            "or %%bl,%%al\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "mov $0x20,%%al\n"
            "out %%al,%%dx\n"
            "1:"
            "nop\n"
            "in %%dx,%%al\n"
            "and $0x88,%%al\n"
            "cmp $0x08,%%al\n"
            "jnz 1b\n"
            "sub $7,%%dx\n"
            "rep insw\n" ::"a"(bReadNumber),
            "c"((DWORD)bReadNumber << 8), "d"(wPort[bNo >> 1]), "D"(lpvBuffer),
            "m"(dwLBAAddress), "b"((BYTE)(((bNo & 1) << 4) | 0xE0)));
}

VOID DevHardDiskWrite(BYTE bNo, DWORD dwLBAAddress, BYTE bWriteNumber, LPVOID lpvBuffer) {
    __asm__("out %%al,%%dx\n"
            "inc %%dx\n"
            "mov %4,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "and $0x0F,%%al\n"
            "or %%bl,%%al\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "mov $0x30,%%al\n"
            "out %%al,%%dx\n"
            "1:"
            "nop\n"
            "in %%dx,%%al\n"
            "and $0x88,%%al\n"
            "cmp $0x08,%%al\n"
            "jnz 1b\n"
            "sub $7,%%dx\n"
            "rep outsw\n" ::"a"(bWriteNumber),
            "c"((DWORD)bWriteNumber << 8), "d"(wPort[bNo >> 1]), "S"(lpvBuffer),
            "m"(dwLBAAddress), "b"((BYTE)(((bNo & 1) << 4) | 0xE0)));
}

BOOL DevHardDiskExisted(BYTE bNo, DWORD dwLBAAddress) {
    REG BOOL bRet = FALSE;
    __asm__("out %%al,%%dx\n"
            "inc %%dx\n"
            "mov %5,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "shr $8,%%eax\n"
            "and $0x0F,%%al\n"
            "or %%bl,%%al\n"
            "out %%al,%%dx\n"
            "inc %%dx\n"
            "mov $0x20,%%al\n"
            "out %%al,%%dx\n"
            "1:"
            "nop\n"
            "in %%dx,%%al\n"
            "test $1,%%al\n"
            "jnz 1f\n"
            "and $0x88,%%al\n"
            "cmp $0x08,%%al\n"
            "jnz 1b\n"
            "sub $7,%%dx\n"
            "2:"
            "in %%dx,%%ax\n"
            "loop 2b\n"
            "mov $1,%0\n"
            "1:"
            : "+r"(bRet)
            : "a"(1), "b"((BYTE)(((bNo & 1) << 4) | 0xE0)), "c"(0x100),
                "d"(wPort[bNo >> 1]), "m"(dwLBAAddress));
    return bRet;
}
